/**
 * 请求工具类
 */
import { STORAGE_KEYS, BASE_URL, ROUTES, HTTP_STATUS } from '../constants';

// 请求选项接口
export interface RequestOptions extends UniApp.RequestOptions {
  showLoading?: boolean;
  loadingText?: string;
  showError?: boolean;
  errorTitle?: string;
  retry?: number;
  retryDelay?: number;
  timeout?: number;
}

// 响应接口
export interface ResponseData<T = any> {
  code: number;
  message: string;
  data: T;
}

// 默认配置
const defaultOptions: Partial<RequestOptions> = {
  showLoading: true,
  loadingText: '加载中...',
  showError: true,
  errorTitle: '请求失败',
  retry: 0,
  retryDelay: 1000,
  timeout: 30000
};

// 请求队列
let requestQueue: number = 0;

// 显示加载提示
const showLoading = (title: string) => {
  if (requestQueue === 0) {
    uni.showLoading({
      title,
      mask: true
    });
  }
  requestQueue++;
};

// 隐藏加载提示
const hideLoading = () => {
  requestQueue--;
  if (requestQueue === 0) {
    uni.hideLoading();
  }
};

// 显示错误提示
const showError = (message: string, title: string) => {
  uni.showToast({
    title: message || title,
    icon: 'none',
    duration: 2000
  });
};

// 请求拦截器
const requestInterceptor = (config: RequestOptions) => {
  // 合并默认配置
  const options = { ...defaultOptions, ...config };
  
  // 获取token
  const token = uni.getStorageSync(STORAGE_KEYS.TOKEN);
  
  // 如果有token，添加到请求头
  if (token) {
    options.header = {
      ...options.header,
      'Authorization': `Bearer ${token}`
    };
  }
  
  // 添加基础URL
  if (options.url && !options.url.startsWith('http')) {
    options.url = options.url;
  }
  
  // 添加超时时间
  if (options.timeout) {
    options.timeout = options.timeout;
  }
  
  // 显示加载提示
  if (options.showLoading) {
    showLoading(options.loadingText || '加载中...');
  }
  
  return options;
};

// 响应拦截器
const responseInterceptor = (response: any, config: RequestOptions) => {
  // 隐藏加载提示
  if (config.showLoading) {
    hideLoading();
  }
  
  // 如果返回的状态码为401，说明token已过期或无效
  if (response.statusCode === HTTP_STATUS.UNAUTHORIZED) {
    // 清除本地存储的token和用户信息
    uni.removeStorageSync(STORAGE_KEYS.TOKEN);
    uni.removeStorageSync(STORAGE_KEYS.USER_INFO);
    
    // 跳转到登录页
    uni.navigateTo({
      url: ROUTES.LOGIN
    });
    
    return Promise.reject(new Error('登录已过期，请重新登录'));
  }
  
  // 如果返回的状态码不是200，说明请求出错
  if (response.statusCode !== HTTP_STATUS.SUCCESS) {
    // 显示错误提示
    if (config.showError) {
      showError(response.data?.message, config.errorTitle || '请求失败');
    }
    
    return Promise.reject(new Error(response.data?.message || '请求失败'));
  }
  
  // 业务逻辑错误处理
  if (response.data && response.data.code !== 0) {
    // 显示错误提示
    if (config.showError) {
      showError(response.data.message, config.errorTitle || '请求失败');
    }
    
    return Promise.reject(new Error(response.data.message || '请求失败'));
  }
  
  // 返回数据
  return response.data;
};

/**
 * 发送请求
 * @param options 请求选项
 * @returns Promise
 */
const request = <T = any>(options: RequestOptions): Promise<ResponseData<T>> => {
  // 请求拦截
  const config = requestInterceptor(options);
  
  // 发送请求
  return new Promise((resolve, reject) => {
    let retryCount = 0;
    
    const sendRequest = () => {
      uni.request({
        ...config,
        success: (res) => {
          // 响应拦截
          try {
            const data = responseInterceptor(res, config);
            resolve(data as ResponseData<T>);
          } catch (error) {
            // 如果配置了重试，并且重试次数小于配置的重试次数，则重试
            if (config.retry && retryCount < config.retry) {
              retryCount++;
              setTimeout(() => {
                sendRequest();
              }, config.retryDelay);
            } else {
              reject(error);
            }
          }
        },
        fail: (err) => {
          // 隐藏加载提示
          if (config.showLoading) {
            hideLoading();
          }
          
          // 如果配置了重试，并且重试次数小于配置的重试次数，则重试
          if (config.retry && retryCount < config.retry) {
            retryCount++;
            setTimeout(() => {
              sendRequest();
            }, config.retryDelay);
          } else {
            // 显示错误提示
            if (config.showError) {
              showError('网络错误，请稍后重试', config.errorTitle || '请求失败');
            }
            
            reject(err);
          }
        }
      });
    };
    
    sendRequest();
  });
};

/**
 * GET请求
 * @param url 请求地址
 * @param data 请求参数
 * @param options 其他选项
 * @returns Promise
 */
export const get = <T = any>(url: string, data?: any, options?: Partial<RequestOptions>): Promise<ResponseData<T>> => {
  return request<T>({
    url,
    data,
    method: 'GET',
    ...options
  });
};

/**
 * POST请求
 * @param url 请求地址
 * @param data 请求参数
 * @param options 其他选项
 * @returns Promise
 */
export const post = <T = any>(url: string, data?: any, options?: Partial<RequestOptions>): Promise<ResponseData<T>> => {
  return request<T>({
    url,
    data,
    method: 'POST',
    ...options
  });
};

/**
 * PUT请求
 * @param url 请求地址
 * @param data 请求参数
 * @param options 其他选项
 * @returns Promise
 */
export const put = <T = any>(url: string, data?: any, options?: Partial<RequestOptions>): Promise<ResponseData<T>> => {
  return request<T>({
    url,
    data,
    method: 'PUT',
    ...options
  });
};

/**
 * DELETE请求
 * @param url 请求地址
 * @param data 请求参数
 * @param options 其他选项
 * @returns Promise
 */
export const del = <T = any>(url: string, data?: any, options?: Partial<RequestOptions>): Promise<ResponseData<T>> => {
  return request<T>({
    url,
    data,
    method: 'DELETE',
    ...options
  });
};

/**
 * 上传文件
 * @param url 请求地址
 * @param filePath 文件路径
 * @param name 文件对应的 key
 * @param formData 其他表单数据
 * @param options 其他选项
 * @returns Promise
 */
export const uploadFile = <T = any>(
  url: string,
  filePath: string,
  name: string = 'file',
  formData?: Record<string, any>,
  options?: Partial<RequestOptions>
): Promise<ResponseData<T>> => {
  // 合并默认配置
  const config = { ...defaultOptions, ...options };
  
  // 获取token
  const token = uni.getStorageSync(STORAGE_KEYS.TOKEN);
  
  // 如果有token，添加到请求头
  const header: Record<string, string> = {};
  if (token) {
    header['Authorization'] = `Bearer ${token}`;
  }
  
  // 添加基础URL
  if (url && !url.startsWith('http')) {
    url = url;
  }
  
  // 显示加载提示
  if (config.showLoading) {
    showLoading(config.loadingText || '上传中...');
  }
  
  return new Promise((resolve, reject) => {
    let retryCount = 0;
    
    const sendRequest = () => {
      uni.uploadFile({
        url,
        filePath,
        name,
        formData,
        header,
        success: (res) => {
          // 隐藏加载提示
          if (config.showLoading) {
            hideLoading();
          }
          
          if (res.statusCode === HTTP_STATUS.SUCCESS) {
            try {
              const data = JSON.parse(res.data);
              resolve(data as ResponseData<T>);
            } catch (error) {
              reject(new Error('解析响应数据失败'));
            }
          } else {
            // 如果配置了重试，并且重试次数小于配置的重试次数，则重试
            if (config.retry && retryCount < config.retry) {
              retryCount++;
              setTimeout(() => {
                sendRequest();
              }, config.retryDelay);
            } else {
              // 显示错误提示
              if (config.showError) {
                showError(res.errMsg || '上传失败', config.errorTitle || '上传失败');
              }
              
              reject(new Error(res.errMsg || '上传失败'));
            }
          }
        },
        fail: (err) => {
          // 隐藏加载提示
          if (config.showLoading) {
            hideLoading();
          }
          
          // 如果配置了重试，并且重试次数小于配置的重试次数，则重试
          if (config.retry && retryCount < config.retry) {
            retryCount++;
            setTimeout(() => {
              sendRequest();
            }, config.retryDelay);
          } else {
            // 显示错误提示
            if (config.showError) {
              showError('网络错误，请稍后重试', config.errorTitle || '上传失败');
            }
            
            reject(err);
          }
        }
      });
    };
    
    sendRequest();
  });
};

export default {
  get,
  post,
  put,
  del,
  uploadFile,
  request
}; 